﻿using Microsoft.AspNetCore.Http;
using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Basedatas;
using mozhi.smarterp.Finance.Enums;
using Mozhi.Abp.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;

namespace mozhi.smarterp.Finance.Finances.Services.EndPeriodProcess
{
    public class ProfitLossEndPeriodProcessor : EndPeriodProcessorBase<AccountBalance>
    {
        public ProfitLossEndPeriodProcessor(EndPeriodProcessItem item, int period, IServiceProvider serviceProvider) : base(item, period, serviceProvider)
        {
        }

        protected override async Task<EndPeriodProcessResult> HandleDataAsync()
        {
            //取综合本位币金额
            _data = _data.Where(x => x.CurrencyId == null && x.DimensionGroupValueId == null).ToList();

            ///本年利润科目
            var account4103 = GetAccount(GetEndPeriodProcessSettingAsync("4103")?.CustomAccountCode);


            //取所有的损益类科目
            //收益类科目
            var revenueAccounts = _accounts.Where(x => x.AccountType == Enums.AccountType.OperatingRevenue || x.AccountType == Enums.AccountType.OtherRevenue).Where(x => x.IsLeaf).ToList();

            //费用类科目
            var expenseAccounts = _accounts.Where(x => x.AccountType == AccountType.OperatingCostsAndTaxes || x.AccountType == AccountType.OtherLosses
            || x.AccountType == AccountType.PeriodCharge || x.AccountType == AccountType.IncomeTax).Where(x => x.IsLeaf).ToList();


            //1. 获取本年到现在的收益
            var revenueAccountIds = revenueAccounts.Select(x => x.Id).ToList();

            var incomeAmount = _data.Where(x => revenueAccountIds.Contains(x.AccountId)).Sum(x => x.CreditAmount.ToDecimal(2) - x.DebitAmount.ToDecimal(2));

            //2. 获取本年费用金额
            var expenseAccountIds = expenseAccounts.Select(x => x.Id).ToList();

            var expenseAmount = _data.Where(x => expenseAccountIds.Contains(x.AccountId)).Sum(x => x.DebitAmount.ToDecimal(2) - x.CreditAmount.ToDecimal(2));

            var transferAmount = incomeAmount - expenseAmount;

            var result = new EndPeriodProcessResult(_guidGenerator.Create(), _item.Id, _period, EndPeriodProcessType.TransferProfitLoss);

            result.Change(true, false, null, transferAmount, false);

            var items = GetResultItems(result.Id, incomeAmount, expenseAmount);

            items.ForEach(item =>
            {
                result.AddItem(item);

            });

            return result;
        }

        protected override async Task<Journal> HandleGenerateJournalAsync()
        {
            _data = _data.Where(x => x.DimensionGroupValueId != null && x.CurrencyId != null).ToList();

            ///本年利润科目
            var account4103 = GetFirstLeafAccount(GetEndPeriodProcessSettingAsync("4103")?.CustomAccountCode);

            //收益类科目
            var revenueAccounts = _accounts.Where(x => x.AccountType == AccountType.OperatingRevenue || x.AccountType == AccountType.OtherRevenue).Where(x => x.IsLeaf).ToList();

            //费用类科目
            var expenseAccounts = _accounts.Where(x => x.AccountType == AccountType.OperatingCostsAndTaxes || x.AccountType == AccountType.OtherLosses
            || x.AccountType == AccountType.PeriodCharge || x.AccountType == AccountType.IncomeTax).Where(x => x.IsLeaf).ToList();


            //1. 获取本年到现在的收益
            var revenueAccountIds = revenueAccounts.Select(x => x.Id).ToList();

            var incomeBalances = _data.Where(x => revenueAccountIds.Contains(x.AccountId)).ToList();

            //2. 获取本年费用金额
            var expenseAccountIds = expenseAccounts.Select(x => x.Id).ToList();

            var expenseBalances = _data.Where(x => expenseAccountIds.Contains(x.AccountId)).ToList();

            //测算结果
            var measureResult = await GetEndPeriodResultAsync();

            var amount = measureResult.MeasureValue;

            var journalMananger = _serviceProvider.GetService(typeof(JournalManager)) as JournalManager;

            var defaultJournalNumberPrefix = await GetJournalDefaultNumberPrefix();

            var journal = await journalMananger.Create(_guidGenerator.Create(), defaultJournalNumberPrefix.Id, _period.ToLastDayDateTime());

            var journalEntriesDebit = await GetJournalItemsAsync(incomeBalances, 0, AccountDirectionType.Debit);

            var journalEntriesCreadit = await GetJournalItemsAsync(expenseBalances, journalEntriesDebit.Count, AccountDirectionType.Credit);

            var journalItems = journalEntriesDebit;

            journalItems.AddRange(journalEntriesCreadit);

            //再加上本年利润科目凭证分录
            journalItems.Add(await GetJournalItemAsync("结转损益", (amount >= 0 ? amount : -amount).Value, account4103, null, 
                journalItems.Count, amount >= 0 ? AccountDirectionType.Credit : AccountDirectionType.Debit));

            await journalMananger.ChangeItems(journal, journalItems);

            return journal;

        }

        #region
        private List<EndPeriodProcessResultItem> GetResultItems(Guid resultId , decimal? incomeAmount, decimal? expenseAmount)
        {
            var result = new List<EndPeriodProcessResultItem>();

            //设置子处理项
            result.Add(new EndPeriodProcessResultItem(_guidGenerator.Create(), resultId, "本期收入合计", (incomeAmount ?? 0).ToString(), 1, 1, false));


            result.Add(new EndPeriodProcessResultItem(_guidGenerator.Create(), resultId, "本期费用合计", (expenseAmount ?? 0).ToString(), 1, 2, false));

            return result;
        }


        private async Task<List<JournalItem>> GetJournalItemsAsync(List<AccountBalance> balances, int startIndex, AccountDirectionType direction)
        {
            var result = new List<JournalItem>();

            if (balances == null || balances.Count == 0)
                return result;

            foreach (var balance in balances)
            {
                var matchAccount = _accounts.FirstOrDefault(x => x.Id == balance.AccountId);

                //找不到科目，处理不了
                if (matchAccount == null)
                    continue;

                var journalEntry = await GetJournalItemAsync(balance, matchAccount, startIndex, direction);

                result.Add(journalEntry);
                startIndex++;
            }

            return result;
        }

        private async Task<JournalItem> GetJournalItemAsync(AccountBalance balance, Account account, int index, AccountDirectionType direction)
        {
            var amount = direction == AccountDirectionType.Debit ? balance.CreditAmount.ToDecimal(2) - balance.DebitAmount.ToDecimal(2) : balance.DebitAmount.ToDecimal(2) - balance.CreditAmount.ToDecimal(2);

            var baseCurrencyId = (await _organizationRepository.GetAsync()).StandardCurrencyId;

            var debitAmount = direction == AccountDirectionType.Debit ? (decimal?)amount : null;
            var creditAmount = direction == AccountDirectionType.Credit ? (decimal?)amount : null;

            var journalEntry = new JournalItem(_guidGenerator.Create(), "结转损益", account.Id, direction, balance.DimensionGroupValueId, baseCurrencyId.Value, 1, amount, debitAmount, creditAmount, index);

            return journalEntry;
        }

        #endregion
    }
}
